package com.gator.spring.framework.aop.intercept;

import com.gator.spring.framework.aop.aspect.PABLO_JoinPoint;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author PABLO
 * @Date 2022/5/8 17:20
 * @Desc 切点method的拦截器链（动态连接点），提供执行链条上节点的 process 方法
 */
public class PABLO_MethodInvocation implements PABLO_JoinPoint {
    //代理对象
    private Object proxy;
    //切点方法
    private Method method;
    //被代理的实例对象
    private Object target;
    //切点方法的参数列表
    private Object[] arguments;
    //目标方法拦截器上的链集合，即每个method对应的通知集合
    private List<Object> interceptorsAndDynamicMethodMatchers;
    //目标类的class
    private Class<?> targetClass;

    private Map<String, Object> userAttributes;

    //定义一个索引，从-1开始来记录当前拦截器执行的位置
    private int currentInterceptorIndex = -1;

    public PABLO_MethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        this.method = method;
        this.arguments = arguments;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    /**
     * @Description: 真正执行拦截器链的方法
     * 调用完毕会转到链的下一个拦截器上，执行完毕后最后执行目标方法
     * @Author: PABLO
     * @Date: 2022/5/9 12:41
     * @Params: []
     * @Return: java.lang.Object
     **/
    public Object proceed() throws Throwable {
        //如果Interceptor执行完了，则执行joinPoint 即目标方法
        if (Objects.isNull(this.interceptorsAndDynamicMethodMatchers)
                || this.interceptorsAndDynamicMethodMatchers.isEmpty()
                || this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(this.target, this.arguments);
        }
        //获取下一个拦截器节点
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //拦截器链上的每个节点必须是PABLO_MethodInterceptor规范
        if (interceptorOrInterceptionAdvice instanceof PABLO_MethodInterceptor) {
            //获得切点的某一个具体的拦截器，如前置 后置  异常通知拦截器等
            PABLO_MethodInterceptor mi = (PABLO_MethodInterceptor) interceptorOrInterceptionAdvice;
            //如调用com.gator.spring.framework.aop.aspect.PABLO_MethodBeforeAdviceInterceptor.invoke
            return mi.invoke(this);
        } else {
            //动态匹配失败时,略过当前PABLO_MethodInterceptor,调用下一个Interceptor
            return proceed();
        }
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public Object[] getArguments() {
        return this.arguments;
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public void setUserAttribute(String key, Object value) {
        if (value != null) {
            if (this.userAttributes == null) {
                this.userAttributes = new HashMap<String, Object>();
            }
            this.userAttributes.put(key, value);
        } else {
            if (this.userAttributes != null) {
                this.userAttributes.remove(key);
            }
        }
    }

    @Override
    public Object getUserAttribute(String key) {
        return (this.userAttributes != null ? this.userAttributes.get(key) : null);
    }
}
